/*
 * Copyright (C) 2017-2018 Samuel Wall
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package uk.co.samuelwall.materialtaptargetprompt.extras;

import ohos.agp.render.Path;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import uk.co.samuelwall.materialtaptargetprompt.utils.Constants;

import org.jetbrains.annotations.Range;

/**
 * Used to render the prompt focal.
 *
 * @since 2021-06-21
 */
public abstract class PromptFocal implements PromptUIElement {
    /**
     * PromptOptions
     */
    protected PromptOptions mPromptOptions;

    /**
     * Should the ripple be drawn.
     */
    protected boolean isDrawRipple;

    /**
     * The alpha value for the ripple.
     */
    protected int mBaseRippleAlpha;

    /**
     * Sets whether the ripple is drawn around the focal.
     *
     * @param isRipple True to draw the ripple.
     */
    public void setDrawRipple(final boolean isRipple) {
        isDrawRipple = isRipple;
    }

    /**
     * Sets the alpha value to use for the ripple colour.
     *
     * @param rippleAlpha The ripple alpha value between 0 - 255
     */
    public void setRippleAlpha(final @Range(from = 0, to = 255) int rippleAlpha) {
        mBaseRippleAlpha = rippleAlpha;
    }

    /**
     * Get the focal path to be drawn. Override this to support a transparent focal colour.
     *
     * @return The path used to draw the focal
     */
    public Path getPath() {
        return null;
    }

    /**
     * Calculate the point on the focal edge based on the angle.
     * This is called after {@link #prepare(PromptOptions, float, float)} or
     * {@link #prepare(PromptOptions, int[])}.
     *
     * Base implementation assumes that focal is a rectangle.
     *
     * @param angle The angle with 0 based on the right.
     * @param padding The padding added to the focal bounds.
     * @return The calculated point
     */

    public Point calculateAngleEdgePoint(float angle, final float padding) {
        // Calculate the x and y on the focal from the angle calculated
        final RectFloat bounds = this.getBounds();
        final float angleRadians = (float) Math.toRadians(angle);
        final float sin = (float) Math.sin(angleRadians);
        final float cos = (float) Math.cos(angleRadians);
        final float dx1 = (bounds.getWidth() + padding) / (cos > 0 ? Constants.NUM_2 : Constants.NUM_F2);
        final float dy1 = (bounds.getHeight() + padding) / (sin > 0 ? Constants.NUM_2 : Constants.NUM_F2);

        // Could go to part way along the target bounds but risk cutting off corners
        return new Point(bounds.getCenter().getPointX() + dx1, bounds.getCenter().getPointY() + dy1);
    }

    /**
     * Set the focal colour.
     *
     * @param colour Int colour.
     */
    public abstract void setColour(int colour);

    /**
     * Get the focal bounds at scale 1.
     *
     * @return The screen area that the focal is drawn in at scale 1.
     */

    public abstract RectFloat getBounds();

    /**
     * Setup the focal ready for rendering when targeting a view, called prior to first render.
     *
     * @param options The option that the prompt was built from.
     * @param promptViewPosition The prompt views screen position.
     */
    public abstract void prepare(PromptOptions options, int[] promptViewPosition);

    /**
     * Setup the focal ready for rendering when targeting a point on the screen, called prior to first render.
     *
     * @param options The option that the prompt was built from.
     * @param targetX The target screen x position.
     * @param targetY The target screen y position.
     */
    public abstract void prepare(PromptOptions options, float targetX, float targetY);

    /**
     * Update the ripple around the focal.
     *
     * @param revealModifier The amount to scale the ripple by where a 1 value is the same size as the focal.
     * @param alphaModifier The amount to modify the ripple alpha by.
     */
    public abstract void updateRipple(
            @Range(from = 0, to = 2) float revealModifier,
            @Range(from = 0, to = 1) float alphaModifier);
}
